<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
<script>

// 原型

// prototype原型（显式原型）
// 每一个函数对象都有一个prototype属性（Function.prototype除外）
// 定义函数后js引擎会给函数自动添加prototype属性

/* // 自定义函数
var f1 = function (){}
function f2(){}
var f3 = new Function()
console.log( f1.prototype )// {constructor: ƒ1}原型对象 普通对象
console.log( f2.prototype )// {constructor: ƒ2}原型对象 普通对象
console.log( f3.prototype )// {constructor: ƒ3}原型对象 普通对象

// 内置函数
console.log( Number.prototype )// 普通对象
console.log( String.prototype )// 普通对象
console.log( Boolean.prototype )// 普通对象
console.log( Array.prototype )// 普通对象
console.log( Object.prototype )// 普通对象
console.log( Function.prototype )// 函数对象 *
console.log( (Function.prototype).prototype )// undefined *

// 其他对象
var obj = {}
var arr = []
var str = 'hello'
var num = 123
console.log( obj.prototype )// undefined
console.log( arr.prototype )// undefined
console.log( str.prototype )// undefined
console.log( num.prototype )// undefined */


// prototype原型的作用？
// 给函数的prototype添加属性/方法时，所有函数的实例对象都可以共享这些属性/方法
// 简单讲，同一类对象可以共享/同一个构造函数创建的多个对象可以共享（继承）

/* Number.prototype.hehe = '呵呵'
var num1 = 123 // Number类型
var num2 = 456 // Number类型
var str1 = 'hello' // String类型
console.log( num1.hehe )// 呵呵
console.log( num2.hehe )// 呵呵
console.log( str1.hehe )// undefined ?

Object.prototype.haha = '哈哈'
var obj1 = {a:1} // Object类型
var obj2 = {a:2} // Object类型
var str2 = 'world' // String类型
console.log( obj1.haha )// 哈哈
console.log( obj2.haha )// 哈哈
console.log( str2.haha )// 哈哈 ? */


// __proto__原型（隐式原型）
// 每一个对象都有隐藏的__proto__属性（null和undefined除外）
// 对象的__proto__属性，值为创建该对象的构造函数的prototype

/* var str = 'abc'
var num = 123
var boo = true
var obj = {}
var arr = []
var fun = function (){}
console.log( str.__proto__ )// String.prototype
console.log( num.__proto__ )// Number.prototype
console.log( boo.__proto__ )// Boolean.prototype
console.log( obj.__proto__ )// Object.prototype
console.log( arr.__proto__ )// Array.prototype
console.log( fun.__proto__ )// Function.prototype

console.log( Number.__proto__ )// Function.prototype
console.log( String.__proto__ )// Function.prototype
console.log( Boolean.__proto__ )// Function.prototype
console.log( Object.__proto__ )// Function.prototype
console.log( Array.__proto__ )// Function.prototype */


// __proto__原型的作用？
// __proto__原型的作用是维护原型链
Object.prototype.xixi = '嘻嘻'
var obj = {a:1}
var str = 'abc'
var num = 123

console.log( obj.xixi )// 嘻嘻
// 1.当我们访问对象的一个属性时，JS引擎先在对象自身查找该属性
// 先在obj自身查找xixi属性，没有xixi属性

// 2.JS引擎通过对象的__proto__查找上层原型对象
// obj.__proto__ -> Object.prototype，有xixi属性，返回属性值'嘻嘻'

console.log( str.xixi )// 嘻嘻
// 1.当我们访问对象的一个属性时，JS引擎先在对象自身查找该属性
// 先在str自身查找xixi属性，没有xixi属性

// 2.JS引擎通过对象的__proto__查找上层原型对象
// str.__proto__ -> String.prototype，也没有xixi属性

// 3.JS引擎依次向上层原型对象查找xixi属性，一直到null
// (str.__proto__).__proto__ -> Object.prototype，有xixi属性，返回属性值'嘻嘻'

console.log( num.xixi )// 嘻嘻
// 1.当我们访问对象的一个属性时，JS引擎先在对象自身查找该属性
// 先在num自身查找xixi属性，没有xixi属性

// 2.JS引擎通过对象的__proto__查找上层原型对象
// num.__proto__ -> Number.prototype，也没有xixi属性

// 3.JS引擎依次向上层原型对象查找xixi属性，一直到null
// (num.__proto__).__proto__ -> Object.prototype，有xixi属性，返回属性值'嘻嘻'

// 所以，从对象的__proto__开始，连接的所有对象就是我们通常说的 '原型链'
// str.__proto__ -> str.__proto__.__proto__ -> str.__proto__.__proto__.__proto__
// String.prototype -> Object.prototype -> null

</script>
</body>
</html>